package routers

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/core/chaincode/shim/ext/cid"
	pb "github.com/hyperledger/fabric/protos/peer"
	"strconv"
	"time"
)

type UmetripNormalChaincode struct {
}

func (t *UmetripNormalChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	//return shim.Success(nil)
	//fmt.Println("init succuss")
	return shim.Success([]byte("init succuss"))
}

func (t *UmetripNormalChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	fmt.Println("UmetripNormalChaincode Invoke")
	function, args := stub.GetFunctionAndParameters()
	if function == "queryHistory" {
		// Make payment of X units from A to B
		return t.queryHistory(stub, args)
	} else if function == "deposit" {
		// Deletes an entity from its state
		return t.deposit(stub, args)
	} else if function == "queryTransaction" {
		// the old "Query" is now implemtned in invoke
		return t.queryTransaction(stub, args)
	} else if function == "depositContentOnly" {
		return t.depositContentOnly(stub, args)
	}

	return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
}

// Transaction makes payment of X units from A to B
func (t *UmetripNormalChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 2 {
		return shim.Error("Incorrect number of arguments. Expecting 3")
	}

	var key string
	var value string
	var err error

	key = args[0]
	value = args[1]

	if len(key) <= 0 || len(value) <= 0 {
		return shim.Error("invoke data format exception")
	}
	////json str 转map
	//var dat map[string]interface{}
	//json.Unmarshal([]byte(value), &dat)
	//dat["action"] = action
	//dat["channel"] = channel
	//var mjson, _ =json.Marshal(&dat)
	//value = string(mjson)

	fmt.Printf("invoke begin stroe/read:%s", key+"_"+value)
	err = stub.PutState(key, []byte(value))
	fmt.Printf("invoke end store/read:%s", key+"_"+value)

	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success([]byte("invoke umetrip normal chaincode success"))
	//
	//var A, B string    // Entities
	//var Aval, Bval int // Asset holdings
	//var X int          // Transaction value
	//var err error
	//
	//if len(args) != 3 {
	//	return shim.Error("Incorrect number of arguments. Expecting 3")
	//}
	//
	//A = args[0]
	//B = args[1]
	//
	//// Get the state from the ledger
	//// TODO: will be nice to have a GetAllState call to ledger
	//Avalbytes, err := stub.GetState(A)
	//if err != nil {
	//	return shim.Error("Failed to get state")
	//}
	//if Avalbytes == nil {
	//	return shim.Error("Entity not found")
	//}
	//Aval, _ = strconv.Atoi(string(Avalbytes))
	//
	//Bvalbytes, err := stub.GetState(B)
	//if err != nil {
	//	return shim.Error("Failed to get state")
	//}
	//if Bvalbytes == nil {
	//	return shim.Error("Entity not found")
	//}
	//Bval, _ = strconv.Atoi(string(Bvalbytes))
	//
	//// Perform the execution
	//X, err = strconv.Atoi(args[2])
	//if err != nil {
	//	return shim.Error("Invalid transaction amount, expecting a integer value")
	//}
	//Aval = Aval - X
	//Bval = Bval + X
	//fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
	//
	//// Write the state back to the ledger
	//err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	//if err != nil {
	//	return shim.Error(err.Error())
	//}
	//
	//err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	//if err != nil {
	//	return shim.Error(err.Error())
	//}
	//
	//return shim.Success(nil)
}

// Deletes an entity from state
func (t *UmetripNormalChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}

	A := args[0]

	// Delete the key from the state in ledger
	err := stub.DelState(A)
	if err != nil {
		return shim.Error("Failed to delete state")
	}

	return shim.Success(nil)
}

func (t *UmetripNormalChaincode) depositContentOnly(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var userId string
	userId, err := cid.GetID(stub)
	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting key to depositContentOnly")
	}
	var content = args[0]

	if len(content) <= 0 {
		return shim.Error("Incorrect key . Expecting right orderId  to depositContentOnly")
	}

	Md5Inst := md5.New()
	Md5Inst.Write([]byte(userId + content))
	key := Md5Inst.Sum(nil)
	var fabricKey = hex.EncodeToString(key)
	err = stub.PutState(fabricKey, []byte(content))
	if err != nil {
		return shim.Error("Failed to deposit state")
	}
	var buffer bytes.Buffer
	buffer.WriteString(fabricKey)

	return shim.Success(buffer.Bytes())
}

func (t *UmetripNormalChaincode) deposit(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var userId string
	var err error
	userId, err = cid.GetID(stub)
	if len(args) != 2 {
		return shim.Error("Incorrect number of arguments. Expecting key to deposit")
	}
	var orderId = args[0]
	var content = args[1]

	if len(orderId) <= 0 {
		return shim.Error("Incorrect key . Expecting right orderId  to deposit")
	}

	Md5Inst := md5.New()
	Md5Inst.Write([]byte(userId + orderId))
	key := Md5Inst.Sum(nil)
	var fabricKey = hex.EncodeToString(key)
	err = stub.PutState(fabricKey, []byte(content))
	if err != nil {
		return shim.Error("Failed to deposit state")
	}
	var buffer bytes.Buffer
	buffer.WriteString(fabricKey)

	return shim.Success(buffer.Bytes())
}

// query callback representing the query of a chaincode
func (t *UmetripNormalChaincode) queryTransaction(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var key string
	var err error

	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting key to queryTransaction")
	}

	key = args[0]

	if len(key) <= 0 {
		return shim.Error("Incorrect key . Expecting right key  to query")
	}

	fmt.Printf("query begin store/read: %s", key)
	// Get the state from the ledger
	var fabricKey = key
	resultsIterator, err := stub.GetState(fabricKey)
	fmt.Printf("query end store/read: %s", key)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + fabricKey + "\"}"
		return shim.Error(jsonResp)
	}

	if resultsIterator == nil {
		jsonResp := "{\"Error\":\"Nil amount for " + fabricKey + "\"}"
		return shim.Error(jsonResp)
	}

	return shim.Success(resultsIterator)
}
func (t *UmetripNormalChaincode) queryHistory(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var key string
	var err error

	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
	}

	key = args[0]

	if len(key) <= 0 {
		return shim.Error("Incorrect key . Expecting right key  to query")
	}

	fmt.Printf("query begin store/read: %s", key)
	// Get the state from the ledger
	var fabricKey = key
	resultsIterator, err := stub.GetHistoryForKey(fabricKey)
	fmt.Printf("query end store/read: %s", key)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + fabricKey + "\"}"
		return shim.Error(jsonResp)
	}

	if resultsIterator == nil {
		jsonResp := "{\"Error\":\"Nil amount for " + fabricKey + "\"}"
		return shim.Error(jsonResp)
	}

	defer resultsIterator.Close()

	// buffer is a JSON array containing historic values for the marble
	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false
	if resultsIterator.HasNext() {
		for resultsIterator.HasNext() {
			response, err := resultsIterator.Next()
			if err != nil {
				return shim.Error(err.Error())
			}
			// Add a comma before array members, suppress it for the first array member
			if bArrayMemberAlreadyWritten == true {
				buffer.WriteString(",")
			}
			buffer.WriteString("{\"TxId\":")
			buffer.WriteString("\"")
			buffer.WriteString(response.TxId)
			buffer.WriteString("\"")

			buffer.WriteString(", \"Value\":")
			// if it was a delete operation on given key, then we need to set the
			//corresponding value null. Else, we will write the response.Value
			//as-is (as the Value itself a JSON marble)
			if response.IsDelete {
				buffer.WriteString("null")
			} else {
				buffer.WriteString(string(response.Value))
			}

			buffer.WriteString(", \"Timestamp\":")
			buffer.WriteString("\"")
			buffer.WriteString(time.Unix(response.Timestamp.Seconds+28800, int64(response.Timestamp.Nanos)).String())
			buffer.WriteString("\"")

			buffer.WriteString(", \"IsDelete\":")
			buffer.WriteString("\"")
			buffer.WriteString(strconv.FormatBool(response.IsDelete))
			buffer.WriteString("\"")

			buffer.WriteString("}")
			bArrayMemberAlreadyWritten = true
		}
		buffer.WriteString("]")
	} else {
		return shim.Success(nil)
	}

	fmt.Printf("- getHistoryForMarble returning:\n%s\n", buffer.String())
	return shim.Success(buffer.Bytes())
}

func main() {
	err := shim.Start(new(UmetripNormalChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}

	var value = "{\"ip\": \"127.0.0.1\", \"device\": \"ABESSF0023\"}"
	//json str 转map
	var dat map[string]interface{}
	json.Unmarshal([]byte(value), &dat)
	dat["action"] = "action"
	dat["channel"] = "channel"
	var mjson, _ = json.Marshal(&dat)
	value = string(mjson)
	println(value)
}
